package com.lnu_devteam.zongce.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.lnu_devteam.zongce.constant.ThreadPoolConstant;
import com.lnu_devteam.zongce.constant.UserConstant;
import com.lnu_devteam.zongce.model.entity.User;
import com.lnu_devteam.zongce.service.UserService;
import com.lnu_devteam.zongce.utils.Md5Utils;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @author xbaozi
 * @description Excel导入监听器
 * @date 2023/3/24 12:09
 **/
@Slf4j
public class DataListener extends AnalysisEventListener<User> {
    /**
     * 每隔1000条存储数据库，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 1000;

    /**
     * 需要传递一个service进来对业务逻辑进行操作，即存放数据进数据库中
     */
    private final UserService userService;

    /**
     * 自定义线程池
     */
    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
            ThreadPoolConstant.corePoolSize,
            ThreadPoolConstant.maxPoolSize,
            ThreadPoolConstant.keepAliveSeconds,
            ThreadPoolConstant.unit,
            ThreadPoolConstant.workQueue
    );

    /**
     * 任务集合
     */
    List<CompletableFuture<Void>> futureList = new ArrayList<>();

    /**
     * 缓存的数据
     */
    List<User> list = new ArrayList<>(BATCH_COUNT);

    /**
     * 每次创建Listener的时候把service传进来
     */
    public DataListener(UserService userService) {
        this.userService = userService;
    }

    boolean flag = true;

    /**
     * @description 读取数据所执行的逻辑
     * @author xBaozi
     * @date 17:14 2022/5/3
     **/
    @Override
    public void invoke(User instance, AnalysisContext analysisContext) {
        if (instance == null) {
            log.debug("读取失败");
            return;
        }
        if (StringUtils.isBlank(instance.getUAccount())) {
            log.debug("账号为空");
            return;
        }
        // 密码为默认前缀+学号/工号
        instance.setUPassword(
                Md5Utils.getMd5String(UserConstant.DEFAULT_PWD_PRE + instance.getUAccount())
        );
        list.add(instance);
        // 达到BATCH_COUNT存储一次数据库，防止超大数据量在内存造成OOM
        if (list.size() >= BATCH_COUNT) {
            this.saveBatch(list);
            list = new ArrayList<>(BATCH_COUNT);
        }
    }

    /**
     * @description 所有数据读取完毕之后将数据存放到数据库中
     * @author xBaozi
     * @date 17:15 2022/5/3
     **/
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 确保最后遗留的数据也存储到数据库
        this.saveBatch(list);
        CompletableFuture.allOf(futureList.toArray(new CompletableFuture[]{})).join();
        list.clear();
    }

    /**
     * @description 将数据存放到数据库中
     * @author xBaozi
     * @date 17:09 2022/5/3
     **/
    private void saveBatch(final List<User> list) {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            List<User> tempList = list;
            List<String> accountList = new ArrayList<>();
            for (User user : tempList) {
                accountList.add(user.getUAccount());
            }
            List<String> existUserAccount = userService.list(
                    new LambdaQueryWrapper<User>()
                            .select(User::getUAccount)
                            .in(User::getUAccount, accountList)
            ).stream().map(User::getUAccount).collect(Collectors.toList());
            tempList = tempList.stream().filter(user -> {
                return !existUserAccount.contains(user.getUAccount());
            }).collect(Collectors.toList());
            if (!tempList.isEmpty()) {
                userService.saveBatch(tempList);
            }
        }, executor);
        futureList.add(future);
    }
}